import java.util.HashMap;
import java.util.Collection;

/** Represents a graph, which consists of many nodes.
    @author Ian Helmke, Dan King
*/
class Graph<KT, NI, LI> {
  private HashMap<KT, INode<NI, LI>> nodes;
  private String name;

  /** The Constructor.
      @param name The name of this graph.
  */
  public Graph(String name) {
    this(name, new HashMap<KT, INode<NI, LI>>());
  }

  /** The Other Constructor.
      @param name The name of this graph.
      @param nodes A hashmap of nodes that represent this graph.
  */
  public Graph(String name, HashMap<KT, INode<NI, LI>> nodes) {
    this.name = name;
    this.nodes = nodes;
  }

  /** Attempts to retrieve a node with the specified name.
      @param key The key of the node to retrieve.
  */
  public INode<NI, LI> getNode(KT key) {
    return this.nodes.get(key);
  }

  /**
   * returns the entire list of nodes
   * @return ArrayList the entire list of nodes
   **/
  public Collection<INode<NI, LI>> getNodes() {
    return nodes.values();
  }

  /** Adds the given node to this graph under the given key.
      @param key the key of the node to be added.
      @param node the physical node object to be added.
  */
  public void addNode(KT key, INode<NI, LI> node) {
    this.nodes.put(key, node);
  }

  /** Clears all nodes from this Graph **/
  public void clearNodes() {
    this.nodes = new HashMap<KT, INode<NI, LI>>();
  }

  /** Accepts a graph traverser, and has that traverser visit this graph
      and every node in this graph (the nodes, in turn, will tell it to
      visit the links)
      @param traverser The traverser that will accept the individual items
                       of this graph.
  */
  public void acceptTraverser(IGraphTraverser<KT, NI, LI> traverser) {
    traverser.acceptGraph(this);

    for (INode<NI, LI> n : this.nodes.values()) {
      traverser.acceptNode(n);
      for (ILink<LI, NI> l : n.getLinks()) {
        traverser.acceptLink(l, n);
      }
    }
  }
}
